package com.easylive.entity.component;

import com.easylive.entity.config.AppConfig;
import com.easylive.entity.constants.Constants;
import com.easylive.entity.dto.SysSettingDto;
import com.easylive.entity.dto.TokenUserInfoDto;
import com.easylive.entity.dto.UploadingFileDto;
import com.easylive.entity.dto.VideoPlayInfoDTO;
import com.easylive.entity.enums.DateTimePatternEnum;
import com.easylive.entity.po.CategoryInfo;
import com.easylive.entity.po.VideoInfoFilePost;
import com.easylive.redis.RedisUtils;
import com.easylive.utils.DateUtil;
import com.easylive.utils.StringTools;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Author: yudaxian
 * @Description: 操作redis的方法
 * @DateTime: 2024/10/16 22:55
 **/
@Component
public class RedisComponent {
    @Resource
    private RedisUtils redisUtils;

    @Resource
    private AppConfig appConfig;

    public String saveCheckCode(String code) {
        String checkCodeKey = UUID.randomUUID().toString();
        redisUtils.setex(Constants.REDIS_KEY_CHECK_CODE + checkCodeKey, code, Constants.REDIS_KEY_EXPIRES_ONE_MINUTE);
        return checkCodeKey;
    }

    public String getCheckCodeByKey(String checkCodeKey) {
        return (String) redisUtils.get(Constants.REDIS_KEY_CHECK_CODE + checkCodeKey);
    }

    public void deleteCheckCodeByKey(String checkCodeKey) {
        redisUtils.delete(Constants.REDIS_KEY_CHECK_CODE + checkCodeKey);
    }

    public void saveTokenInfo(TokenUserInfoDto tokenUserInfoDto) {
        String token = UUID.randomUUID().toString();
        tokenUserInfoDto.setExpireAt(System.currentTimeMillis() + Constants.REDIS_KEY_EXPIRES_ONE_DAY * 7);
        tokenUserInfoDto.setToken(token);

        redisUtils.setex(Constants.REDIS_KEY_TOKEN_WEB + token, tokenUserInfoDto, Constants.REDIS_KEY_EXPIRES_ONE_DAY * 7);
    }


    public void updateTokenInfo(TokenUserInfoDto tokenUserInfoDto) {
        redisUtils.setex(Constants.REDIS_KEY_TOKEN_WEB + tokenUserInfoDto.getToken(), tokenUserInfoDto, Constants.REDIS_KEY_EXPIRES_ONE_DAY * 7);
    }

    public TokenUserInfoDto getTokenUserInfoDto(String token) {
        return (TokenUserInfoDto) redisUtils.get(Constants.REDIS_KEY_TOKEN_WEB + token);
    }

    public void deleteTokenUserInfoDto(String token) {
        redisUtils.delete(Constants.REDIS_KEY_TOKEN_WEB + token);
    }

    public String saveTokenInfo4Admin(String account) {
        String token = UUID.randomUUID().toString();
        redisUtils.setex(Constants.REDIS_KEY_TOKEN_ADMIN + token, account, Constants.REDIS_KEY_EXPIRES_ONE_DAY);
        return token;
    }

    public String getAdminAccountByToken(String token) {
        return (String) redisUtils.get(Constants.REDIS_KEY_TOKEN_ADMIN + token);
    }

    public void deleteToken4Admin(String token) {
        redisUtils.delete(Constants.REDIS_KEY_TOKEN_ADMIN + token);
    }

    public void saveCategoryInfo(List<CategoryInfo> list) {
        redisUtils.set(Constants.REDIS_KEY_CATEGORY_LIST, list);
    }

    public List<CategoryInfo> getCategoryInfo() {
        return (List<CategoryInfo>) redisUtils.get(Constants.REDIS_KEY_CATEGORY_LIST);
    }

    public String savePreUploadVideoInfo(String userId, String fileName, Integer chunks) {
        // 生成一个唯一的uploadId
        String uploadId = StringTools.getRandomString(Constants.LENGTH_20);

        // 构建fileDto对象，将基本信息存储到Redis中
        UploadingFileDto fileDto = new UploadingFileDto();
        fileDto.setUploadId(uploadId);
        fileDto.setFileName(fileName);
        fileDto.setChunks(chunks);
        fileDto.setChunkIndex(0);

        // 构建文件夹路径
        String day = DateUtil.format(new Date(), DateTimePatternEnum.YYYYMMDD.getPattern());
        String filePath = day + "/" + userId + "/" + uploadId;
        String folder = appConfig.getProjectFolder() + Constants.FILE_FOLDER + Constants.FILE_TEMP + filePath;

        File fileFolder = new File(folder);
        if (!fileFolder.exists()) {
            fileFolder.mkdirs();
        }
        fileDto.setFilePath(filePath);

        redisUtils.setex(Constants.REDIS_KEY_PRE_UPLOAD_VIDEO + userId + ":" + uploadId + ":",
                fileDto, Constants.REDIS_KEY_EXPIRES_ONE_DAY);

        return uploadId;
    }

    public UploadingFileDto getUploadFileDto(String userId, String uploadId) {
        return (UploadingFileDto) redisUtils.get(Constants.REDIS_KEY_PRE_UPLOAD_VIDEO + userId + ":" + uploadId + ":");
    }

    public SysSettingDto getSysSetting() {
        SysSettingDto sysSettingDto = (SysSettingDto) redisUtils.get(Constants.REDIS_KEY_SYS_SETTING);
        if (ObjectUtils.isEmpty(sysSettingDto)) {
            sysSettingDto = new SysSettingDto();
        }

        return sysSettingDto;
    }

    public void saveSysSetting(SysSettingDto sysSettingDto) {
        redisUtils.set(Constants.REDIS_KEY_SYS_SETTING, sysSettingDto);
    }

    public void updateUploadFileDto(String userId, UploadingFileDto uploadFileDto) {
        redisUtils.setex(Constants.REDIS_KEY_PRE_UPLOAD_VIDEO + userId + ":" + uploadFileDto.getUploadId() + ":",
                uploadFileDto, Constants.REDIS_KEY_EXPIRES_ONE_DAY);
    }

    public void delUploadFileDto(String userId, String uploadId) {
        redisUtils.delete(Constants.REDIS_KEY_PRE_UPLOAD_VIDEO + userId + ":" + uploadId + ":");
    }

    public void addFile2DelMQ(String videoId, List<String> deleteFilePathList) {
        /**
         * 将要删除的文件路径列表放入Redis的列表中，并设置过期时间为7天，审核通过后，这个文件才能被删除
         */
        redisUtils.lpushAll(Constants.REDIS_KEY_FILE_DEL + videoId, deleteFilePathList, Constants.REDIS_KEY_EXPIRES_ONE_DAY * 7);
    }

    public List<String> getDelFileList(String videoId) {
        return redisUtils.getQueueList(Constants.REDIS_KEY_FILE_DEL + videoId);
    }

    public void addFile2TransferMQ(List<VideoInfoFilePost> addFileList) {
        redisUtils.lpushAll(Constants.REDIS_KEY_FILE_ADD, addFileList, 0);
    }

    /**
     * 使用list结构实现轻量的消息队列，lpush实现入队，rpop实现出队
     * @return
     */
    public VideoInfoFilePost getFileTransferQueue() {
        return (VideoInfoFilePost) redisUtils.rpop(Constants.REDIS_KEY_FILE_ADD);
    }

    public void deleteUploadFileDto(String userId, String uploadId) {
        redisUtils.delete(Constants.REDIS_KEY_PRE_UPLOAD_VIDEO + userId + ":" + uploadId + ":");
    }

    public void clearDeleteFileList(String videoId) {
        redisUtils.delete(Constants.REDIS_KEY_FILE_DEL + videoId);
    }

    /**
     * 监听视频播放人数
     * @return
     * @param fileId
     * @param deviceId 浏览器唯一标识，前端生成的
     */
    public Integer reportVideoPlayOnline(String fileId, String deviceId) {
        String userPlayOnlineKey = String.format(Constants.REDIS_KEY_VIDEO_PLAY_COUNT_USER, fileId, deviceId);

        // 当前播放视频的总数量
        String playOnlineCountKey = String.format(Constants.REDIS_KEY_VIDEO_PLAY_COUNT_ONLINE, fileId);

        /**
         * 如果第一次进入，看视频，不存在就设置8秒，前端是轮询，5秒一次
         */
        if (!redisUtils.keyExists(userPlayOnlineKey)) {
            redisUtils.setex(userPlayOnlineKey, fileId, Constants.REDIS_KEY_EXPIRES_ONE_SECOND * 8);
            // 对总人数的值进行自增操作，并返回数量
            return redisUtils.incrementex(playOnlineCountKey, Constants.REDIS_KEY_EXPIRES_ONE_SECOND * 10).intValue();
        }

        // 有人在看就续期
        redisUtils.expire(playOnlineCountKey, Constants.REDIS_KEY_EXPIRES_ONE_SECOND * 10);
        redisUtils.expire(userPlayOnlineKey, Constants.REDIS_KEY_EXPIRES_ONE_SECOND * 8);

        Integer count = (Integer) redisUtils.get(playOnlineCountKey);
        // 这还不够，需要监听user的失效时间，如果失效了， 人数需要-1
        return count == null ? 1 : count;
    }

    /**
     * 减少播放数量
     */
    public void decreaseVideoPlayOnlineCount(String key) {
        redisUtils.decrement(key);
    }

    public void addKeywordCount(String keyword) {
        redisUtils.zaddCount(Constants.REDIS_KEY_SEARCH_KEYWORD_COUNT, keyword);
    }

    public List<String> getKeyWordTop(Integer top) {
        return redisUtils.getZSetList(Constants.REDIS_KEY_SEARCH_KEYWORD_COUNT, top - 1);
    }

    public void addVideoPlay(VideoPlayInfoDTO videoPlayInfoDTO) {
        redisUtils.lpush(Constants.REDIS_KEY_QUEUE_PLAY, videoPlayInfoDTO, null);
    }

    public VideoPlayInfoDTO getVideoPlayInfo() {
        return (VideoPlayInfoDTO) redisUtils.rpop(Constants.REDIS_KEY_QUEUE_PLAY);
    }

    public void recordVideoPlayCount(String videoId) {
        // 按天的计数器
        String date = DateUtil.format(new Date(), DateTimePatternEnum.YYYY_MM_DD.getPattern());
        redisUtils.incrementex(Constants.REDIS_KEY_VIDEO_PLAY_COUNT + date + ":" + videoId, Constants.REDIS_KEY_EXPIRES_ONE_DAY * 2);
    }

    public Map<String, Integer> getVideoPlayCount(String date) {
        return redisUtils.getBatch(Constants.REDIS_KEY_VIDEO_PLAY_COUNT + date);
    }
}
